#pragma once
#include <SimpleDef.h>
#define PAGE_SIZE (0x1000)
#define PAGE_DIRECTORY_SIZE (0x1000)
#define PAGE_TABLE_SIZE (0x1000)
/* 页目录项 */
#define PDE_PRESENT (1)
#define PDE_WRITEABLE (1 << 1)
#define PDE_USER (1 << 2)
#define PDE_PAGE_LEVEL_WRITE_THROUGH (1 << 3)
#define PDE_PAGE_LEVEL_CACHE_DISABLE (1 << 4)
#define PDE_ACCESSED (1 << 5)
/* 脏位，只在用做 4 MiB 页表索引时有效 */
#define PDE_DIRTY (1 << 6)
/* // PS 位 clear： 指向页表；set： 指向 4 MiB 的页面 */
#define PDE_PAGE_SIZE (1 << 7)
#define PDE_GLOBAL (1 << 8)
#define PDE_ALLOCATED (1 << 9)
/* 页表项 */
#define PTE_PRESENT (1)
#define PTE_WRITEABLE (1 << 1)
#define PTE_USER (1 << 2)
#define PTE_PAGE_LEVEL_WRITE_THROUGH (1 << 3)
#define PTE_PAGE_LEVEL_CACHE_DISABLE (1 << 4)
#define PTE_ACCESSED (1 << 5)
#define PTE_DIRTY (1 << 6)
#define PTE_PAGE_ATTRIBUTE_TABLE (1 << 7)
#define PTE_GLOBAL (1 << 8)
#define PTE_ALLOCATED (1 << 9)
// typedef struct __PageTableInfo
// {
//     short sFirstAvailableEntry; /* 页表中自前向后第一条可用 PTE 的索引（序号） */
//     short scPageTableEntriesInUse; /* 页表中的页表项数量 */
// } PageTableInfo, *LPPageTableInfo;
typedef QWORD IntGateDescriptor; /* 中断门描述符 */
typedef QWORD GlobalDescriptor; /* 全局描述符*/
typedef DWORD PageDirectoryEntry; /* 页目录项 */
typedef PageDirectoryEntry *LPPageDirectoryEntry;
typedef DWORD PageTableEntry; /* 页表项 */
typedef PageTableEntry *LPPageTableEntry;
/* 解析虚拟地址中的页目录索引 */
#define RESOLVE_PDE_INDEX(VIRTUAL_ADDRESS) (((SIZE_T)(VIRTUAL_ADDRESS) & 0xFFC00000) >> 22)
/* 解析虚拟地址中的页表索引 */
#define RESOLVE_PTE_INDEX(VIRTUAL_ADDRESS) (((SIZE_T)(VIRTUAL_ADDRESS) & 0x3FF000) >> 12)
/* 解析虚拟地址中的页内偏移 */
#define RESOLVE_INPAGE_OFFSET(VIRTUAL_ADDRESS) (((VIRTUAL_ADDRESS) & 0xFFF))
/* 由页目录索引、页表索引、页内偏移计算虚拟地址 */
#define GENERATE_VIRTUAL_ADDRESS(PDE_INDEX, PTE_INDEX, INPAGE_OFFSET) (((PDE_INDEX) << 22) + ((PTE_INDEX) << 12) + (INPAGE_OFFSET))
/* 内核虚拟空间起始地址 IVT、BootLoader（可覆盖） */
#define KERNEL_SPACE_BASE GENERATE_VIRTUAL_ADDRESS(768, 0, 0)
/* 内存管理错误状态码 */
#define MEMORY_BITMAP_INVALID_OFFSET (0xFFFFFFFF) /* 无效的内存位图偏移地址 */
/* 分配页面状态码 */
#define PAGE_ALLOCATE_SUCCESS (0) /* 虚拟页面或物理页框分配成功 */
#define PAGE_ALLOCATE_CONTIGUOUS_PAGES_NOT_FOUND (1) /* 找不到指定数量的连续虚拟页面 */
/* 释放页面状态码 */
#define PAGE_FREE_SUCCESS (0) /* 成功释放页面 */
#define PAGE_FREE_UNALLOCATED (1) /* 释放未被分配的页面 */
/* 分配页框状态码 */
#define FRAME_ALLOCATE_SUCCESS (0) /* 成功分配物理页框 */
#define FRAME_ALLOCATE_INSUFFICIENT (1) /* 物理页框不足 */
/* 释放页框状态码 */
#define FRAME_FREE_SUCCESS (0) /* 成功释放页框 */
#define FRAME_FREE_UNALLOCATED (1) /* 试图释放未被分配的页框*/
/* 缺页处理状态码 */
#define PAGE_FAULT_SUCCESS (0) /* 成功处理缺页中断 */
#define PAGE_FAULT_UNALLOCATED (1) /* 访问的页面未预分配 */
#define PAGE_FAULT_INSUFFICIENT (2) /* 物理内存空间不足 */
#define PAGE_FAULT_WRITE_DENIED (6) /* 尝试写入只读的页面 */
#define PAGE_FAULT_ACCESS_DENIED (7) /* 用户进程试图访问内核地址空间 */
// extern PageTableInfo g_PageTableInfo[1024]; /* 1024 张页表的信息 */
void QueryMemoryInfo();
/*
@brief 自后向前搜索位图，获取位图中可用的一位，并将该位清空
@param cdBitmap 位图的大小（以 DWORD 为单位）
@param dwaBitmap 位图数组
@return 可用的位在位图中的相对于位图起始处偏移量（以位为单位）
*/
extern DWORD __fastcall AquireAvailableBit(DWORD cdBitmap, DWORD dwaBitmap[]);
/*
@brief 释放位图中被占用的位，将对应位置位
@param nBitOffset 释放的位在位图中的偏移（以位为单位）
@param dwaBitmap 位图数组
@return 若释放的位已经置位（说明未分配），则返回 PRIMITIVE_MEMORY_BITMAP_INVALID_OFFSET；
        否则，返回被释放的位在位图 DWORD 数组中的索引，即被释放的位在哪个 DWORD 中。
*/
extern DWORD __fastcall ReleaseOccupiedBit(DWORD nBitOffset, DWORD dwaBitmap[]);
LPVOID AllocatePageForKernel(int ncPages, DWORD dwControlBits);
LPVOID AllocatePageForUser(int ncPages, DWORD dwAttrbuteBits);
BOOL AllocateFrame(LPPageTableEntry lpVirtualAddress);
BOOL HandlePageFault(DWORD dwPrivilegeLevel);
DWORD FreeFrame(DWORD_PTR dwlpPhysicalFrame);
DWORD FreePage(LPVOID lpVirtualPage, DWORD dwCount);
LPVOID AllocateStackForUser(int nPages);
LPVOID AllocateStackForKernel();
